﻿using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace HenrryTools.Tools.Common
{
    /// <summary>
    ///新 Http工具类
    /// </summary>
    public class HttpHelper
    {
        private static readonly string DefaultUserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36";
        /// <summary>  
        /// 创建GET方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param> 
        /// <param name="headers">请求的超时时间</param>  
        /// <param name="parameters">随同请求GET的参数名称及参数值字典</param>  
        /// <param name="requestEncoding">编码类型 utf-8</param>  
        /// <param name="contenType">发送HTTP请求时所用的请求头ContentType</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <param name="timeout">请求响应默认超时时长（毫秒）</param>  
        /// <returns></returns>  
        public static string CreateRequestWithGET(string url, Dictionary<string, string> headers, Dictionary<string, string> parameters, Encoding requestEncoding, string contenType, CookieCollection cookies, int timeout = 30000)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }



            if (parameters != null && parameters.Count > 0)
            {
                url = FormatGetParametersToUrl(url, parameters, requestEncoding);
            }


            HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
            request.Method = "GET";
            SetHeaderValue(request.Headers, headers);
            request.UserAgent = DefaultUserAgent;
            if (!string.IsNullOrEmpty(contenType))
            {
                request.ContentType = contenType;
            }
            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
                request.Timeout = timeout;
            }

            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();

            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;
            }

            using (StreamReader reader = new StreamReader(response.GetResponseStream(), requestEncoding))
            {
                return reader.ReadToEnd();
            }
        }


        /// <summary>  
        /// 创建POST方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="headers">随同请求POST的请求头名称及请求头值字典</param>  
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="contenType">发送HTTP请求时所用的请求头ContentType</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <param name="timeout">请求响应默认超时时长（毫秒）</param>  
        /// <returns></returns>  
        public static string CreateRequestWithPOST(string url, Dictionary<string, string> headers, byte[] parameters, Encoding requestEncoding, string contenType, CookieCollection cookies, int timeout = 30000)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request = null;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            request.Method = "POST";
            request.ContentType = contenType;
            request.UserAgent = DefaultUserAgent;
            SetHeaderValue(request.Headers, headers);

            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
                request.Timeout = timeout;
            }
            //发送body内容,json格式
            using (Stream stream = request.GetRequestStream())
            {
                if (parameters != null) stream.Write(parameters, 0, parameters.Length);
            }

            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();

            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;
            }

            using (StreamReader reader = new StreamReader(response.GetResponseStream(), requestEncoding))
            {
                return reader.ReadToEnd();
            }
        }



        /// <summary>  
        /// 创建POST方式的HTTP请求  
        /// </summary>  
        /// <param name="url">请求的URL</param>  
        /// <param name="headers">随同请求POST的请求头名称及请求头值字典</param>  
        /// <param name="parameters">随同请求POST的参数名称及参数值字典</param>  
        /// <param name="requestEncoding">发送HTTP请求时所用的编码</param>  
        /// <param name="contenType">发送HTTP请求时所用的请求头ContentType</param>  
        /// <param name="cookies">随同HTTP请求发送的Cookie信息，如果不需要身份验证可以为空</param>  
        /// <returns></returns>  
        public static string CreateRequestWithPUT(string url, Dictionary<string, string> headers, byte[] parameters, Encoding requestEncoding, string contenType, CookieCollection cookies)
        {
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException("url");
            }
            if (requestEncoding == null)
            {
                throw new ArgumentNullException("requestEncoding");
            }
            HttpWebRequest request = null;
            //如果是发送HTTPS请求  
            if (url.StartsWith("https", StringComparison.OrdinalIgnoreCase))
            {
                ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
                request = WebRequest.Create(url) as HttpWebRequest;
                request.ProtocolVersion = HttpVersion.Version10;
            }
            else
            {
                request = WebRequest.Create(url) as HttpWebRequest;
            }
            request.Method = "PUT";
            request.ContentType = contenType;
            request.UserAgent = DefaultUserAgent;
            SetHeaderValue(request.Headers, headers);

            if (cookies != null)
            {
                request.CookieContainer = new CookieContainer();
                request.CookieContainer.Add(cookies);
            }
            //发送body内容,json格式
            using (Stream stream = request.GetRequestStream())
            {
                if (parameters != null) stream.Write(parameters, 0, parameters.Length);
            }

            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();

            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;
            }

            using (StreamReader reader = new StreamReader(response.GetResponseStream(), requestEncoding))
            {
                return reader.ReadToEnd();
            }
        }

        /// <summary>
        /// HttpUploadFile
        /// </summary>
        /// <param name="url">请求地址</param>
        /// <param name="files">文件数组</param>
        /// <param name="data">表单信息</param>
        /// <param name="requestEncoding">编码格式</param>
        /// <returns></returns>
        public static string HttpUploadFile(string url, string[] files, NameValueCollection data, Encoding requestEncoding)
        {
            string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
            byte[] boundarybytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");
            byte[] endbytes = Encoding.ASCII.GetBytes("\r\n--" + boundary + "--\r\n");

            //1.HttpWebRequest
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "multipart/form-data; boundary=" + boundary;
            request.Method = "POST";
            request.KeepAlive = true;
            request.Credentials = CredentialCache.DefaultCredentials;

            using (Stream stream = request.GetRequestStream())
            {
                //1.1 key/value
                string formdataTemplate = "Content-Disposition: form-data; name=\"{0}\"\r\n\r\n{1}";
                if (data != null)
                {
                    foreach (string key in data.Keys)
                    {
                        stream.Write(boundarybytes, 0, boundarybytes.Length);
                        string formitem = string.Format(formdataTemplate, key, data[key]);
                        byte[] formitembytes = requestEncoding.GetBytes(formitem);
                        stream.Write(formitembytes, 0, formitembytes.Length);
                    }
                }

                //1.2 file
                string headerTemplate = "Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: application/octet-stream\r\n\r\n";
                byte[] buffer = new byte[4096];
                int bytesRead = 0;
                for (int i = 0; i < files.Length; i++)
                {
                    stream.Write(boundarybytes, 0, boundarybytes.Length);
                    string header = string.Format(headerTemplate, "file" + (i == files.Length - 1 ? string.Empty : i.ToString()), Path.GetFileName(files[i]));
                    byte[] headerbytes = requestEncoding.GetBytes(header);
                    stream.Write(headerbytes, 0, headerbytes.Length);
                    using (FileStream fileStream = new FileStream(files[i], FileMode.Open, FileAccess.Read))
                    {
                        while ((bytesRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                        {
                            stream.Write(buffer, 0, bytesRead);
                        }
                    }
                }

                //1.3 form end
                stream.Write(endbytes, 0, endbytes.Length);
            }
            //2.WebResponse
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader stream = new StreamReader(response.GetResponseStream()))
            {
                return stream.ReadToEnd();
            }
        }

        private static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors)
        {
            return true; //总是接受  
        }

        /// <summary>
        /// 设置Http Headers
        /// </summary>
        /// <param name="headers"></param>
        /// <param name="name"></param>
        /// <param name="val"></param>
        private static void SetHeaderValue(WebHeaderCollection headers, Dictionary<string, string> keyValues)
        {
            var property = typeof(WebHeaderCollection).GetProperty("InnerCollection", BindingFlags.Instance | BindingFlags.NonPublic);

            if (property != null)
            {
                var conlection = property.GetValue(headers, null) as NameValueCollection;
                if (keyValues != null)
                {
                    foreach (var key in keyValues.Keys)
                    {
                        conlection[key] = keyValues[key];
                    }
                }
            }
        }

        /// <summary>
        /// 格式化Post请求参数
        /// </summary>
        /// <param name="parameters">编码格式</param>
        /// <param name="dataEncoding">编码格式</param>
        /// <param name="contentType">类型</param>
        /// <returns></returns>
        public static byte[] FormatPostParameters(Dictionary<string, string> parameters, Encoding dataEncoding, string contentType)
        {
            string sendContext = "";
            int i = 0;
            if (!string.IsNullOrEmpty(contentType) && contentType.ToLower().Trim() == "application/json")
            {
                sendContext = "{";
            }

            foreach (var para in parameters)
            {
                if (!string.IsNullOrEmpty(contentType) && contentType.ToLower().Trim() == "application/json")
                {
                    if (i > 0)
                    {
                        if (para.Value.StartsWith("{"))
                        {
                            sendContext += string.Format(@",""{0}"":{1}", para.Key, para.Value);
                        }
                        else
                        {
                            sendContext += string.Format(@",""{0}"":""{1}""", para.Key, para.Value);
                        }

                    }
                    else
                    {
                        if (para.Value.StartsWith("{"))
                        {
                            sendContext += string.Format(@"""{0}"":{1}", para.Key, para.Value);
                        }
                        else
                        {
                            sendContext += string.Format(@"""{0}"":""{1}""", para.Key, para.Value);
                        }

                    }
                }
                else
                {
                    if (i > 0)
                    {
                        sendContext += string.Format("&{0}={1}", para.Key, HttpUtility.UrlEncode(para.Value, dataEncoding));
                    }
                    else
                    {
                        sendContext = string.Format("{0}={1}", para.Key, HttpUtility.UrlEncode(para.Value, dataEncoding));
                    }
                }

                i++;
            }

            if (!string.IsNullOrEmpty(contentType) && contentType.ToLower().Trim() == "application/json")
            {
                sendContext += "}";
            }

            byte[] data = dataEncoding.GetBytes(sendContext);
            return data;
        }

        /// <summary>
        /// 将字符串编码为Base64字符串
        /// </summary>
        /// <param name="str">要编码的字符串</param>
        public static string Base64Encode(string str)
        {
            byte[] barray;
            barray = Encoding.Default.GetBytes(str);
            return Convert.ToBase64String(barray);
        }

        /// <summary>
        /// 将Base64字符串解码为普通字符串
        /// </summary>
        /// <param name="str">要解码的字符串</param>
        public static string Base64Decode(string str)
        {
            byte[] barray;
            barray = Convert.FromBase64String(str);
            return Encoding.Default.GetString(barray);
        }

        /// <summary>
        /// 格式化Get请求参数
        /// </summary>
        /// <param name="url">URL</param>
        /// <param name="parameters">参数</param>
        /// <param name="paraEncoding">编码格式</param>
        /// <returns></returns>

        private static string FormatGetParametersToUrl(string url, Dictionary<string, string> parameters, Encoding paraEncoding)
        {
            if (url.IndexOf("?") < 0)
                url += "?";
            int i = 0;
            string sendContext = "";
            foreach (var parameter in parameters)
            {
                if (i > 0)
                {
                    sendContext += "&";
                }

                sendContext += HttpUtility.UrlEncode(parameter.Key, paraEncoding)
                       + "=" + HttpUtility.UrlEncode(parameter.Value, paraEncoding);
                ++i;
            }

            url += sendContext;
            return url;
        }
    }





    /// <summary>
    /// 老http
    /// </summary>
    public class HttpTool
    {
        string baseurl = "";

        // log4net.ILog log = log4net.LogManager.GetLogger("log");

        /// <summary>
        /// 
        /// </summary>
        /// <param name="baseurl"></param>
        public HttpTool(string baseurl)
        {
            this.baseurl = baseurl;
        }

        /// <summary>
        /// 发送http请求（独立）
        /// </summary>
        /// <param name="JSONData"></param>
        /// <param name="Url"></param>
        /// <param name="Timeout"></param>
        /// <param name="encode"></param>
        /// <param name="accept"></param>
        /// <param name="ContentType"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public string SendHttpReuqest(string JSONData, string Url, int Timeout = 30000, string encode = "utf-8", string accept = "", string ContentType = "application/json", Dictionary<string, string> headers = null)
        {
            byte[] bytes = Encoding.GetEncoding(encode).GetBytes(JSONData);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);

            if (headers != null)
            {
                foreach (string key in headers.Keys)
                {
                    request.Headers.Add(key, headers[key]);
                }
            }

            request.CookieContainer = new CookieContainer();
            if (accept != "")
            {
                request.Accept = accept;
            }
            request.Method = "POST";

            request.KeepAlive = false;
            request.ProtocolVersion = HttpVersion.Version10;

            request.ContentLength = bytes.Length;
            request.ContentType = ContentType;
            request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)";

            Stream reqstream = request.GetRequestStream();
            reqstream.Write(bytes, 0, bytes.Length);

            //声明一个HttpWebRequest请求  
            request.Timeout = Timeout;
            //设置连接超时时间  
            // request.Headers.Set("Pragma", "no-cache");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream streamReceive = response.GetResponseStream();
            Encoding encoding = Encoding.GetEncoding(encode);


            StreamReader streamReader = new StreamReader(streamReceive, encoding);
            string strResult = streamReader.ReadToEnd();

            //cookies = response.Cookies;
            //log.Info("cookies.cout:" + cookies == null ? " null" : cookies.Count.ToString());

            streamReceive.Dispose();
            streamReader.Dispose();

            return strResult;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="JSONData"></param>
        /// <param name="Url"></param>
        /// <param name="HeaderKey"></param>
        /// <param name="Timeout"></param>
        /// <param name="encode"></param>
        /// <param name="accept"></param>
        /// <param name="ContentType"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public BaseOutDto SendHttpReuqest(string JSONData, string Url, string HeaderKey, int Timeout, string encode, string accept, string ContentType = "application/json", Dictionary<string, string> headers = null)
        {
            BaseOutDto baseOut = new BaseOutDto();
            try
            {
                byte[] bytes = Encoding.GetEncoding(encode).GetBytes(JSONData);

                HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);

                if (headers != null)
                {
                    foreach (string key in headers.Keys)
                    {
                        request.Headers.Add(key, headers[key]);
                    }
                }

                request.CookieContainer = new CookieContainer();
                if (accept != "")
                {
                    request.Accept = accept;
                }
                request.Method = "POST";
                request.KeepAlive = true;
                request.ContentLength = bytes.Length;
                request.ContentType = ContentType;
                request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)";

                Stream reqstream = request.GetRequestStream();
                reqstream.Write(bytes, 0, bytes.Length);

                //声明一个HttpWebRequest请求  
                request.Timeout = Timeout;
                //设置连接超时时间  
                // request.Headers.Set("Pragma", "no-cache");
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream streamReceive = response.GetResponseStream();
                Encoding encoding = Encoding.GetEncoding(encode);



                StreamReader streamReader = new StreamReader(streamReceive, encoding);
                string strResult = streamReader.ReadToEnd();

                string strHeader = response.GetResponseHeader(HeaderKey);

                streamReceive.Dispose();
                streamReader.Dispose();

                baseOut.Code = strHeader;
                baseOut.Msg = strResult;

                return baseOut;
            }
            catch (Exception ex)
            {
                baseOut.Code = "-1";
                baseOut.Msg = ex.Message;
                return baseOut;
            }
        }
        /// <summary>
        /// 发送http请求（独立） 解码gzip
        /// </summary>
        /// <param name="JSONData"></param>
        /// <param name="Url"></param>
        /// <param name="Timeout"></param>
        /// <param name="encode"></param>
        /// <param name="accept"></param>
        /// <param name="ContentType"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public string SendHttpReuqestNew(string JSONData, string Url, int Timeout, string encode, string accept, string ContentType = "application/json", Dictionary<string, string> headers = null)
        {
            byte[] bytes = Encoding.GetEncoding(encode).GetBytes(JSONData);

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);

            if (headers != null)
            {
                foreach (string key in headers.Keys)
                {
                    request.Headers.Add(key, headers[key]);
                }
            }

            request.CookieContainer = new CookieContainer();
            if (accept != "")
            {
                request.Accept = accept;
            }
            request.Method = "POST";
            request.KeepAlive = true;
            request.ContentLength = bytes.Length;
            request.ContentType = ContentType;
            request.UserAgent = "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)";

            Stream reqstream = request.GetRequestStream();
            reqstream.Write(bytes, 0, bytes.Length);

            //声明一个HttpWebRequest请求  
            request.Timeout = Timeout;
            //设置连接超时时间  
            // request.Headers.Set("Pragma", "no-cache");
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Stream streamReceive = new System.IO.Compression.GZipStream(response.GetResponseStream(), System.IO.Compression.CompressionMode.Decompress);
            Encoding encoding = Encoding.GetEncoding(encode);



            StreamReader streamReader = new StreamReader(streamReceive, encoding);
            string strResult = streamReader.ReadToEnd();

            //cookies = response.Cookies;
            //log.Info("cookies.cout:" + cookies == null ? " null" : cookies.Count.ToString());

            streamReceive.Dispose();
            streamReader.Dispose();

            return strResult;
        }

        /// <summary>
        /// xml 参数方式
        /// </summary>
        /// <param name="url"></param>
        /// <param name="Arg"></param>
        /// <param name="ContentType"></param>
        /// <param name="accept"></param>
        /// <param name="encode"></param>
        /// <param name="DeleteAbpPack"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public string ExecXml(string url, string Arg, string ContentType = "application/json", string accept = "", string encode = "utf-8", bool DeleteAbpPack = false, int timeout = 60000)
        {
            string str = SendHttpReuqest(Arg, baseurl + url, timeout, encode, accept, ContentType);
            return str;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="Arg"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="url"></param>
        /// <param name="u"></param>
        /// <param name="accept"></param>
        /// <param name="encode"></param>
        /// <param name="DeleteAbpPack"></param>
        /// <param name="timeout"></param>
        /// <param name="headers"></param>
        /// <returns></returns>
        public T Exec_Arg_T<Arg, T>(string url, Arg u, string accept = "", string encode = "utf-8", bool DeleteAbpPack = false, int timeout = 60000, Dictionary<string, string> headers = null)
         where Arg : new()
         where T : new()
        {
            string str = "";
            try
            {
                str = SendHttpReuqest(JsonConvert.SerializeObject(u), baseurl + url, timeout, encode, accept, "application/json", headers);
                // { "result":{ "msg":"未处理","code":"0","id":0},"targetUrl":null,"success":true,"error":null,"unAuthorizedRequest":false,"__abp":true}


                if (DeleteAbpPack)
                {
                    JObject j = JObject.Parse(str);
                    if ((j["__abp"] + "").ToLower() == "true")

                    {
                        str = j["result"] + "";
                    }
                }

                return JsonConvert.DeserializeObject<T>(str);
            }
            catch (Exception ex)
            {
                //log.Error("序列化json失败：" + str + ex.Message);
                return default(T);
            }

        }
    }



    /// <summary>
    /// DTO基础类   LisDtoConsts  根据这个常量判断返回   0  标识表示成功  1标识失败   99 表示警告
    /// </summary>
    public class BaseOutDto : BaseDto<int>
    {
        /// <summary>
        /// 
        /// </summary>
        public BaseOutDto()
        {
            Code = "0";
            Msg = "";
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="id"></param>
        public BaseOutDto(int id)
            : base(id)
        {
            Code = "0";
        }


        /// <summary>
        /// 返回消息
        /// </summary>
        public string Msg { get; set; }

        /// <summary>
        /// 操作结果  0 表示成功  否则表示失败
        /// </summary>
        public string Code { get; set; }


    }

    /// <summary>
    /// Implements common properties for entity based DTOs.
    /// </summary>
    /// <typeparam name="TPrimaryKey">Type of the primary key</typeparam>
    [Serializable]
    public class BaseDto<TPrimaryKey> : IEntityDto<TPrimaryKey>
    {
        /// <summary>
        /// Id of the entity.
        /// </summary>
        public TPrimaryKey Id { get; set; }

        /// <summary>
        /// Creates a new <see cref="BaseDto{TPrimaryKey}"/> object.
        /// </summary>
        public BaseDto()
        {

        }

        /// <summary>
        /// Creates a new <see cref="BaseDto{TPrimaryKey}"/> object.
        /// </summary>
        /// <param name="id">Id of the entity</param>
        public BaseDto(TPrimaryKey id)
        {
            Id = id;
        }
    }


    /// <summary>
    /// Defines common properties for entity based DTOs.
    /// </summary>
    /// <typeparam name="TPrimaryKey"></typeparam>
    public interface IEntityDto<TPrimaryKey>
    {
        /// <summary>
        /// Id of the entity.
        /// </summary>
        TPrimaryKey Id { get; set; }
    }
}
